#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <sys/types.h>
#include <sys/socket.h>
#include <functional>
#include <pthread.h>
#include "InetAddr.hpp"
#include "LockGuard.hpp"
#include "ThreadPool.hpp"

using task_t = std::function<void()>;

class Route
{
private:
    void CheckOnlineUser(InetAddr& who)
    {
        LockGuard lockguard(&_mutex);
        for (auto &user : _online_user)
        {
            if (user == who)
            {
                LOG(DEBUG, "[%s] is exists\n", who.GetAddrStr().c_str());
                return;
            }
        }
        LOG(DEBUG, "[%s] is not exists, added it\n", who.GetAddrStr().c_str());
        _online_user.push_back(who);
    }

    void Offline(InetAddr& who)
    {
        LockGuard lockguard(&_mutex);
        auto iter = _online_user.begin();
        for (; iter != _online_user.end(); iter++)
        {
            if (*iter == who)
            {
                LOG(DEBUG, "[%s] is offline\n", who.GetAddrStr());
                _online_user.erase(iter);
                break;
            }
        }
    }

    void ForwardHelper(int sockfd, const std::string &msg, InetAddr &who)
    {
        LockGuard lockguard(&_mutex);
        std::string send_msg = "[" + who.GetAddrStr() + "]# " + msg;
        for (auto &user : _online_user)
        {
            struct sockaddr_in peer = user.GetAddr();
            LOG(DEBUG, "Forward msg to [%s], msg: %s\n", user.GetAddrStr().c_str(), send_msg.c_str());
            sendto(sockfd, send_msg.c_str(), send_msg.size(), 0, (struct sockaddr*)&peer, sizeof peer);
        }
    }

public:
    Route()
    {
        pthread_mutex_init(&_mutex, nullptr);
    }

    void Forward(int sockfd, const std::string &msg, InetAddr &who)
    {
        // 检测该消息的发送方是否在列表中 
        // 如果在，什么都不做；如果不在，自动添加到 _online_user 中 
        CheckOnlineUser(who);
        // 此时 who 一定在用户列表 _online_user 里 
        if (msg == "QUIT" || msg == "Q" || msg == "quit" || msg == "q")
        {
            Offline(who);
        }

        // 消息转发 
        // ForwardHelper(sockfd, msg);
        task_t t = std::bind(&Route::ForwardHelper, this, sockfd, msg, who);
        ThreadPool<task_t>::GetInstance()->Equeue(t);
    }

    ~Route()
    {
        pthread_mutex_destroy(&_mutex);
    }

private:
    std::vector<InetAddr> _online_user;
    pthread_mutex_t _mutex;
};

